package inutan.game.service;

import inutan.common.constant.DataConstant;
import inutan.common.context.FlowContext;
import inutan.common.message.ActionErrorEnum;
import inutan.data.Mission.MissionVal;
import inutan.game.business.GameFlowContext;
import inutan.game.entity.Achievement;
import inutan.game.proto.TaskProto;
import inutan.game.task.TaskStatus;
import inutan.game.storage.StorageContext;
import luban.common.Command;
import luban.task.ResTaskInfo;
import org.ricks.common.exception.MsgException;
import org.ricks.common.utils.DateUtils;
import org.ricks.ioc.anno.Autowired;
import org.ricks.ioc.anno.Bean;
import org.ricks.orm.OrmContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Bean
public class AchievementService {

    @Autowired
    private TaskService taskService;

    /**
    * @Explain --> 获取成就数据
    * @Author yanwang
    * @Date 2023/5/19 13:39
    **/
    public ResTaskInfo getAchieveList(long userId) {
        List<Achievement> achievements = OrmContext.me().multiCacheLoad(Achievement.class,userId);
        return TaskProto.getTaskInfo(achievements);
    }

    /**
    * @Explain --> 接取成就任务
    * @Author yanwang
    * @Date 2023/5/19 13:36
    **/
    public Optional<Achievement> acceptTask(long userId, MissionVal missionData) {
        //判断成就是否存在
        List<Achievement> newTaskList = new ArrayList<>();
        Optional<Achievement> task = Optional.of(OrmContext.me().multiCacheGet(Achievement.class,userId, x -> x.getTaskId() == missionData.id));
        task.ifPresentOrElse(x -> {
            //不存在则新增  且状态为Unopened  则修改状态
            if (x.getState() == TaskStatus.Unopened && taskService.verifyRoleLevel(missionData, userId)) {
                x.setState(TaskStatus.Accept);
                OrmContext.me().update(x);
                newTaskList.add(x);
            }
        }, () -> {
            //存在判断状态且等级满足 等级满足则 CanAccept 不满足则Unopened
            int status = taskService.verifyRoleLevel(missionData, userId) ? TaskStatus.Accept : TaskStatus.Unopened;
            Achievement vo = new Achievement();
            vo.setTaskId(missionData.id);
            vo.setRoleId(userId);
            vo.setState(status);
            vo.setProgress(taskService.getProgress(userId, missionData));
            vo.setCreateTime(DateUtils.current());
            OrmContext.me().insert(vo);
            if (status == TaskStatus.Accept) newTaskList.add(vo);
        });
        return newTaskList.stream().findFirst();
    }

    /**
    * @Explain --> 完成成就任务 前置判断任务是否可完成
    * @Author yanwang
    * @Date 2023/5/19 13:37
    **/
    public void completeTask(GameFlowContext context, MissionVal data) {
        //todo 需判断System 是否开启
        Optional<Achievement> achievement = Optional.of(OrmContext.me().multiCacheGet(Achievement.class,context.getUserId(), x -> x.getTaskId() == data.id));

        achievement.ifPresentOrElse(vo -> {
            ActionErrorEnum.taskNotComplete.assertTrue(vo.getState() == TaskStatus.CanComplete);//任务未完成
            completeAchieve(context, vo, data);
        }, () -> {
            throw new MsgException(ActionErrorEnum.taskNotExist);//任务不存在
        });

    }

    /**
    * @Explain --> 完成成就任务
    * @Author yanwang
    * @Date 2023/5/19 13:37
    **/
    public void completeAchieve(GameFlowContext context, Achievement vo, MissionVal data) {
        vo.setState(TaskStatus.Complete);
        vo.setCompleteTime(DateUtils.current());
        OrmContext.me().update(vo);
        //发放奖励
        context.addProps(context.addPropByReward(data.reward));
        //接取下一个任务
        taskService.doNextTask(data.id, context.getUserId());
    }

    /**
    * @Explain --> 校验成就前置任务是否已完成
    * @Author yanwang
    * @Date 2023/5/19 13:38
    **/
    public boolean verifyAchieveComplete(List<Integer> achieveIds, long userId) {
        List<Integer> achievement=OrmContext.me().multiCacheLoadAll(Achievement.class,userId, x->x.getState() == TaskStatus.Complete).stream().map(x->x.getTaskId()).collect(Collectors.toList());
        if (achievement.size()>0){
            return achievement.containsAll(achieveIds);
        }else return false;
    }

    /**
    * @Explain --> 更新成就任务进度
    * @Author yanwang
    * @Date 2023/5/19 13:38
    **/
    public void doAchievement(GameFlowContext context, int targetType, Predicate<MissionVal> targetBool, TaskService.TaskNumFunction<MissionVal> numFuntion, boolean isAdd){
        long userId = context.getUserId();
        List<Achievement> taskList = OrmContext.me().multiCacheLoadAll(Achievement.class,userId, x -> x.getProgress().containsKey(targetType) && x.getState() == TaskStatus.Accept);
        List<Achievement> taskResult = taskList.stream().map(x -> {
            MissionVal val = StorageContext.tables().getTbMission().get(x.getTaskId());
            if (val != null) {
                if (targetBool.test(val)) {
                    int num = numFuntion.getNum(val);
                    int count = isAdd ? x.getProgress().get(targetType) + num : num;
                    x.getProgress().replace(targetType, count);
                    if (count >= val.numCount) x.setState(TaskStatus.CanComplete);
                    if (count >= val.numCount && !val.ifCheck) completeAchieve(context, x, val);
                    else
                        context.sendResponse(DataConstant.BROADCAST_MESSAGE, Command.UpdateTask, TaskProto.taskInfo(x));
                    return x;
                }
            }
            return null;
        }).collect(Collectors.toList());
        for (Achievement achievement: taskResult) {
            OrmContext.me().update(achievement);
        }
    }

}
